package project.ia04.agents.gui;

import jade.core.AID;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.gui.GuiAgent;
import jade.gui.GuiEvent;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.type.TypeFactory;

import project.ia04.gui.frames.MainFrame;
import project.ia04.utils.Data;
import project.ia04.utils.Staff;
import project.ia04.utils.VideoGame;

public class XAgent extends GuiAgent {
	
	public static int GETCA = 0;
	public static final int GETSTAFF = 1;
	public static final int NEWGAME = 2;
	
	
	
	public static int HIRE = 3;
	public static int FIRE = 4;
	public static int TRAIN = 5;
	public static int COFFEE = 6;
	
	public static final int GETHISTORICAL = 10;
	
	
	
	
	private PropertyChangeSupport pcs = new PropertyChangeSupport(this);

	@Override
	protected void onGuiEvent(GuiEvent arg0) {
		if(arg0.getType() == GETCA)
			addBehaviour(new XAgentGetCABehaviour(arg0.getSource()));
		else if(arg0.getType() == GETSTAFF){
			addBehaviour(new XAgentGetStaffsBehaviour(arg0.getSource()));
		}
		else if(arg0.getType() == NEWGAME){
			addBehaviour(new XAgentInitNewGameBehaviour((String)arg0.getParameter(0),(String)arg0.getParameter(1),
					(String)arg0.getParameter(2),(Float)arg0.getParameter(3)));
		}
		else if(arg0.getType() == TRAIN){
			addBehaviour(new SendTrainBehaviour((String) arg0.getParameter(0)));
		}
		else if(arg0.getType() == COFFEE){
			addBehaviour(new SendCoffeeBehaviour((String) arg0.getParameter(0)));
		}
		else if(arg0.getType() >= XCommandAgent.STEP1 && arg0.getType() <= XCommandAgent.STEP3){
			pcs.firePropertyChange("StaffCommandDialog", arg0.getType(), arg0);
		}
		else if(arg0.getType() == HIRE || arg0.getType() == FIRE){
			addBehaviour(new XAgentStaffFireHireBehaviour((String)arg0.getParameter(0),(int)arg0.getType()));
		}
		else if(arg0.getType() == GETHISTORICAL){
			addBehaviour(new XAgentGetHistorical());
		}
	}

	@Override
	protected void setup() {
		MainFrame args = (MainFrame) getArguments()[0];
		args.setXAgent(this);
		pcs.addPropertyChangeListener(args);
		addBehaviour(new StepExchangeBehaviour());
		addBehaviour(new UpdateProgressBehaviour());
		addBehaviour(new StaffActionBehaviour());
		addBehaviour(new EndGameListener());
		register();
	}

	private void register() {
		DFAgentDescription dfd = new DFAgentDescription();
		ServiceDescription sd = new ServiceDescription();
		sd.setType("IA04Project");
		sd.setName("XAgent");
		dfd.addServices(sd);
		try {
			DFService.register(this, dfd);
		} catch (FIPAException e) {
			e.printStackTrace();
		}
	}
	
	public AID getEnvAgent(){
		DFAgentDescription dfd = new DFAgentDescription();
		ServiceDescription sd = new ServiceDescription();
		sd.setType("IA04Project");
		sd.setName("StudioAgent");
		dfd.addServices(sd);
		try {
			DFAgentDescription[] dfdArray = DFService.search(this, dfd);
			if(dfdArray.length >= 1)
				return dfdArray[0].getName();
		} catch (FIPAException e) {
			e.printStackTrace();
		}
		return null;
	}
	

	
	public void addPropertyChangeListener(PropertyChangeListener l){
		pcs.addPropertyChangeListener(l);
	}


	public void send2Frame(String type, String content) {
		Object ctt = content;
		Object snd = null;
		if(type.equals(Data.GETSTAFFSLIST)){
			ctt = toStaffList(content);
		}
		else if(type.equals(Data.GETHISTORICAL)){
			ctt = toGameList(content);
		}
		else if(type.equals(Data.ENDGAME)){
			ctt = deserialize(content,Data.UNITSELL);
			snd = deserialize(content,Data.FAME);
		}
		pcs.firePropertyChange(type, snd, ctt);
	}

	private int deserialize(String content,String field) {
		ObjectMapper mapper = new ObjectMapper();
		Map<String,Object> map;
		int res = 0;
		try {
			map = mapper.readValue(content,Map.class);
			res = (Integer)map.get(field);
		} catch (JsonParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JsonMappingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return res;
	}

	private ArrayList<VideoGame> toGameList(String content) {
		ObjectMapper mapper = new ObjectMapper();
		Map<String,Object> map ;
		ArrayList<VideoGame> res = null;
		try {
			System.out.println(content);
			map = mapper.readValue(content,TypeFactory.defaultInstance().constructMapType(Map.class,
					TypeFactory.defaultInstance().constructFromCanonical("java.lang.String"),
					TypeFactory.defaultInstance().constructParametricType(ArrayList.class,VideoGame.class)));
			res = (ArrayList<VideoGame>) map.get(Data.GETHISTORICAL);
			
		} catch (JsonParseException e) {
			e.printStackTrace();
		} catch (JsonMappingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return res;
	}

	@SuppressWarnings("unchecked")
	public ArrayList<Staff> toStaffList(String content) {
		ObjectMapper mapper = new ObjectMapper();
		Map<String,Object> map ;
		ArrayList<Staff> res = null;
		try {
			System.out.println(content);
			map = mapper.readValue(content,TypeFactory.defaultInstance().constructMapType(Map.class,
					TypeFactory.defaultInstance().constructFromCanonical("java.lang.String"),
					TypeFactory.defaultInstance().constructParametricType(ArrayList.class,Staff.class)));
			res = (ArrayList<Staff>) map.get(Data.GETSTAFFSLIST);
			
		} catch (JsonParseException e) {
			e.printStackTrace();
		} catch (JsonMappingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return res;
	}

	public void initStep(String conversationId) {
		pcs.firePropertyChange(conversationId, null,conversationId.substring(0,1).toUpperCase()+conversationId.substring(1));
	}
	
	public void updateProgress(HashMap<String,Integer> items){
		pcs.firePropertyChange(Data.UPDATEPROGRESS, null, items);
	}

	public void staffAction(String staffName,String message) {
		pcs.firePropertyChange(Data.STAFFACTION, staffName,message);
	}

	public void initGameProp(String conversationId,Map<String, Object> gameProp) {
		pcs.firePropertyChange(Data.INITGUINEWGAME,null,gameProp);
	}

	public void staffLvlUp(String staffName,int lvl) {
		pcs.firePropertyChange(Data.NEWLVL,staffName, lvl);
		
	}

	public void updateMainProgress(String content) {
		pcs.firePropertyChange(Data.PROGRESS, null,Integer.valueOf(content));
	}

	public void staffStaminaChange(String staffName,int stamina) {
		pcs.firePropertyChange(Data.STAMINA,staffName,stamina);
	}
	

}
